package auth

import (
	"system-admin/config/mysql"
	"system-admin/internal/models"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
)

type RoleAuthRulesWithChecked struct {
	ID          string `json:"id" gorm:"column:id"`
	Title       string `json:"title" gorm:"column:title"`
	Name        string `json:"name" gorm:"column:name"`
	Value       string `json:"value" gorm:"column:value"`
	RuleType    int    `json:"rule_type" gorm:"column:rule_type"`
	PID         string `json:"pid" gorm:"column:pid"`
	Apis        string `json:"-" gorm:"column:apis"`
	DBTableName string `json:"-" gorm:"column:db_table_name"`
	Order       int    `json:"order" gorm:"column:order"`
	CreatedAt   int64  `json:"created_at" gorm:"column:created_at"`
	UpdatedAt   int64  `json:"updated_at" gorm:"column:updated_at"`
	Checked     bool   `json:"checked"`
}

// GetRoleAuthRules 获取角色的权限
func GetRoleAuthRules(roleID string) (interface{}, error) {
	db := mysql.NewDB()
	// 判断角色是否存在
	if roleID != "1" {
		var count int64
		db.Model(&models.Role{}).Where("id = ?", roleID).Count(&count)
		if count <= 0 {
			return nil, errorx.New("角色不存在", -1)
		}
	}

	// 获取角色的权限
	var authRules []models.AuthRule

	// 非管理员
	if roleID != "1" {
		db.Model(&models.RoleAuthRule{}).
			Select("auth_rule.*").
			Joins("JOIN auth_rule ON auth_rule.id = role_auth_rule.rule_id").
			Where("role_auth_rule.role_id = ?", roleID).
			Where("auth_rule.deleted_at IS NULL").
			Order("auth_rule.order").
			Find(&authRules)
	} else { // 管理员
		db.Model(&models.AuthRule{}).
			Select("auth_rule.*").
			Order("auth_rule.order").
			Where("auth_rule.deleted_at IS NULL").
			Find(&authRules)
	}

	if len(authRules) <= 0 {
		return []string{}, nil
	}

	// 将list转为tree
	tree, err := helper.NewTree("ID", "PID").ListToTree("1", authRules)
	if err != nil {
		return []string{}, err
	}
	return tree, nil
}

// GetRoleAuthRules 获取角色的权限规则
func GetRoleAuthRulesWithChecked(loginUserID string, roleID string) (interface{}, error) {
	db := mysql.NewDB()
	// 判断角色是否存在
	var count int64
	db.Model(&models.Role{}).Where("id = ?", roleID).Count(&count)
	if count <= 0 {
		return nil, errorx.New("角色不存在", -1)
	}
	// 获取角色的权限
	var (
		roleAuthRules    []models.AuthRule
		roleAuthRulesMap = make(map[string]bool) // slice转map，方便遍历check
	)
	db.Model(&models.RoleAuthRule{}).
		Select("auth_rule.*").
		Joins("JOIN auth_rule ON auth_rule.id = role_auth_rule.rule_id").
		Where("auth_rule.deleted_at IS NULL").
		Where("role_id = ?", roleID).
		Find(&roleAuthRules)
	for _, roleAuthRule := range roleAuthRules {
		roleAuthRulesMap[roleAuthRule.ID] = true
	}
	// 获取当前登录用户的信息
	var user models.User
	db.Model(&models.User{}).
		Where("id = ?", loginUserID).
		Take(&user)

	// 如果是管理员
	var loginUserAuthRules []models.AuthRule
	if user.IsSuperAdmin == 1 {
		db.Model(&models.AuthRule{}).
			Order("auth_rule.order").
			Where("auth_rule.deleted_at IS NULL").
			Find(&loginUserAuthRules)
	} else {
		db.Model(&models.RoleAuthRule{}).
			Select("auth_rule.*").
			Joins("JOIN auth_rule ON auth_rule.id = role_auth_rule.rule_id").
			Where("auth_rule.deleted_at IS NULL").
			Where("role_auth_rule.role_id = ?", user.RoleID).
			Order("auth_rule.order").
			Find(&loginUserAuthRules)
	}

	// 将角色已有的权限标记为checked
	var roleAuthRulesWithChecked []RoleAuthRulesWithChecked
	for _, loginUserAuthRule := range loginUserAuthRules {
		temp := RoleAuthRulesWithChecked{
			ID:          loginUserAuthRule.ID,
			Title:       loginUserAuthRule.Title,
			Name:        loginUserAuthRule.Name,
			Value:       loginUserAuthRule.Value,
			RuleType:    loginUserAuthRule.RuleType,
			PID:         loginUserAuthRule.PID,
			Apis:        loginUserAuthRule.Apis,
			DBTableName: loginUserAuthRule.DBTableName,
			Order:       loginUserAuthRule.Order,
			CreatedAt:   loginUserAuthRule.CreatedAt,
			UpdatedAt:   loginUserAuthRule.UpdatedAt,
			Checked:     false,
		}
		if roleAuthRulesMap[loginUserAuthRule.ID] {
			temp.Checked = true
		}
		roleAuthRulesWithChecked = append(roleAuthRulesWithChecked, temp)
	}
	// 将list转为tree
	tree, err := helper.NewTree("ID", "PID").ListToTree("1", roleAuthRulesWithChecked)
	if err != nil {
		return nil, err
	}
	return tree, nil
}

// SetRoleAuthRules 设置权限
// loginUserID 当前登录的用户id
// roleID 待设置权限的角色id，ruleIDs 待设置的规则权限
func SetRoleAuthRules(loginUserID string, loginUserRoleID string, roleID string, ruleIDs []string) error {
	db := mysql.NewDB()
	// 如果当前用户不是管理员，则不允许设置
	var loginUserInfo models.User
	db.Model(&models.User{}).Where("id = ?", loginUserID).Take(&loginUserInfo)
	if loginUserInfo.IsAdmin != 1 && loginUserInfo.IsSuperAdmin != 1 {
		return errorx.New("非管理员，没有权限", -1)
	}
	// 判断角色是否存在
	var count int64
	db.Model(&models.Role{}).Where("id = ?", roleID).Count(&count)
	if count <= 0 {
		return errorx.New("角色不存在", -1)
	}
	// 获取用户信息
	var user models.User
	mysql.NewDB().Model(&models.User{}).
		Where("id = ?", loginUserID).
		Take(&user)
	if user.IsSuperAdmin == 1 {
		// 保存角色权限
		return saveRoleAuthRules(roleID, ruleIDs)
	} else {
		// 权限过滤,智能是当前用户拥有的权限
		var filteredRuleIDs []string
		mysql.NewDB().Model(&models.RoleAuthRule{}).
			Joins("JOIN auth_rule ON auth_rule.id = role_auth_rule.rule_id").
			Where("role_auth_rule.role_id = ?", loginUserRoleID).
			Where("role_auth_rule.rule_id IN ?", ruleIDs).
			Pluck("role_auth_rule.rule_id", &filteredRuleIDs)
		// 保存角色权限
		return saveRoleAuthRules(roleID, filteredRuleIDs)
	}
}

// saveRoleAuthRules 保存角色权限规则
func saveRoleAuthRules(roleID string, ruleIDs []string) error {
	var (
		containSyetemRule bool
		containPageRule   bool
	)
	// 过滤掉不存在的权限
	var rules []models.AuthRule
	mysql.NewDB().Model(&models.AuthRule{}).Where("id IN ?", ruleIDs).Find(&rules)
	if len(rules) <= 0 {
		return errorx.New("缺少有效的权限", -1)
	}
	// 必须包含系统和页面
	for _, rule := range rules {
		// 系统
		if rule.RuleType == 1 {
			containSyetemRule = true
		}
		// 页面
		if rule.RuleType == 2 {
			containPageRule = true
		}
	}
	if !containSyetemRule || !containPageRule {
		return errorx.New("必须包含系统及页面权限", -1)
	}

	// 删除掉原有的权限
	mysql.NewDB().Model(&models.RoleAuthRule{}).
		Where("role_id = ?", roleID).
		Delete(&models.RoleAuthRule{})

	//  不存在的就创建
	for _, rule := range rules {
		mysql.NewDB().Model(&models.RoleAuthRule{}).Where(models.RoleAuthRule{
			RoleID: roleID,
			RuleID: rule.ID,
		}).FirstOrCreate(&models.RoleAuthRule{})
	}
	return nil
}
